package xworker.gluon.netty;

import com.google.protobuf.ByteString;
import org.xmeta.ActionContext;
import org.xmeta.Thing;
import org.xmeta.World;
import org.xmeta.util.ExceptionUtil;
import org.xmeta.util.UtilString;
import xworker.dataObject.data.StaticDataManager;
import xworker.dataObject.DataObject;
import xworker.dataObject.DataObjectList;
import xworker.gluon.netty.protocols.GluonMessages;
import xworker.netty.NettyClient;
import xworker.netty.NettyClientListener;
import xworker.netty.NettySession;
import xworker.netty.handlers.message.Handler;

import java.nio.charset.StandardCharsets;

public class ProviderClient {
    static NettyClient nettyClient;
    static ActionContext actionContext = new ActionContext();
    static String providerName;
    static String providerPassword;

    static{
        Thing thing = World.getInstance().getThing("xworker.gluon.netty.ProviderClient");
        nettyClient = thing.doAction("getNettyClient", actionContext);
        nettyClient.addListener(new NettyClientListener() {
            @Override
            public void onConnected(NettyClient nettyClient) {
                DataObject data = getStaticData();
                data.put("connected", true);

                if(providerName != null && providerPassword != null){
                    GluonMessages.RegistProviderReq.Builder builder = GluonMessages.RegistProviderReq.newBuilder();
                    builder.setName(providerName);
                    builder.setPassword(providerPassword);
                    nettyClient.sendMessage(builder.build());
                }
            }

            @Override
            public void onDisconnected(NettyClient nettyClient) {
                DataObject data = getStaticData();
                data.put("connected", false);
                data.put("registed", false);
                getStaticList().clear();
            }

            @Override
            public void onBeforeReconnect(NettyClient nettyClient, long waitReconnectTime) {

            }

            @Override
            public void onClosed(NettyClient nettyClient) {
                DataObject data = getStaticData();
                data.put("connected", false);
                data.put("registed", false);
                getStaticList().clear();
            }

            @Override
            public void onConnectSuccess(NettyClient nettyClient) {

            }

            @Override
            public void onConnectFailure(NettyClient nettyClient, Throwable cause) {
                DataObject data = getStaticData();
                data.put("connected", false);
                data.put("message", ExceptionUtil.toString(cause));
                getStaticList().clear();
            }

            @Override
            public void onConnectCancelled(NettyClient nettyClient) {

            }
        });
    }

    public static DataObject getStaticData(){
        Thing thing = World.getInstance().getThing("xworker.gluon.xapp.provider.StaticDatas");
        return StaticDataManager.getStaticDataManager(thing).dataObject("status");
    }

    public static DataObjectList getStaticList(){
        Thing thing = World.getInstance().getThing("xworker.gluon.xapp.provider.StaticDatas");
        return StaticDataManager.getStaticDataManager(thing).dataObjectList("clientList");
    }

    public static void connect(String host, int port){
        if(nettyClient.isClosed()){
            nettyClient.close();
        }

        nettyClient.setAutoConnect(true);
        nettyClient.setHost(host);
        nettyClient.setPort(port);
        nettyClient.connect();
    }

    public static NettyClient getNettyClient(){
        return nettyClient;
    }

    public static void disconnect(){
        nettyClient.close();
    }

    @Handler(requestClass = GluonMessages.RegistProviderResp.class)
    public static void handleRegistProviderResp(GluonMessages.RegistProviderResp resp, NettySession nettySession){
        DataObject data = getStaticData();
        if(resp.getResult() == 0){
            data.put("registed", true);
            data.put("message", UtilString.getString("lang:d=注册成功！&en=Register successed!", actionContext));
        }else{
            data.put("registed", false);
            data.put("message", UtilString.getString("lang:d=注册失败！&en=Register failue!", actionContext));
        }
    }

    @Handler(requestClass = GluonMessages.ListClientsResp.class)
    public static void handleListClientsResp(GluonMessages.ListClientsResp resp, NettySession nettySession){
        DataObjectList list = getStaticList();
        list.clear();

        for(GluonMessages.Client client : resp.getClientListList()){
            DataObject data = new DataObject("xworker.gluon.xapp.provider.ClientList/@DataObjects/@AbstractDataObject");
            data.put("id", client.getClientId());
            data.put("name", client.getClientName());
            list.add(data);
        }
    }

    @Handler(requestClass = GluonMessages.SendThingToClientResp.class)
    public static void handleSendThingToClientResp(GluonMessages.SendThingToClientResp resp, NettySession nettySession){
        DataObject data = getStaticData();
        if(resp.getResult() == 0){
            data.put("message", UtilString.getString("lang:d=发送成功！&en=Send successed!", actionContext));
        }else{
            data.put("message", UtilString.getString("lang:d=发送失败！&en=Send failure!", actionContext));
        }
    }

    public static void initStaticData(ActionContext actionContext){
        DataObject data = getStaticData();
        data.put("connected", nettyClient.isConnected());
        data.put("registed", false);
    }

    public static void registProvider(String providerName, String providerPassword){
        ProviderClient.providerName = providerName;
        ProviderClient.providerPassword = providerPassword;

        GluonMessages.RegistProviderReq.Builder builder = GluonMessages.RegistProviderReq.newBuilder();
        builder.setName(providerName);
        builder.setPassword(providerPassword);
        nettyClient.sendMessage(builder.build());
    }

    public static void refreshClients(){
        GluonMessages.ListClientsReq.Builder builder = GluonMessages.ListClientsReq.newBuilder();
        nettyClient.sendMessage(builder.build());
    }

    public static void sendThingToClient(Thing thing, long clientId){
        GluonMessages.SendThingToClientReq.Builder builder = GluonMessages.SendThingToClientReq.newBuilder();
        builder.setClientId(clientId);
        builder.setPath(thing.getMetadata().getPath());
        builder.setContent(ByteString.copyFrom(thing.toXML(), StandardCharsets.UTF_8));
        nettyClient.sendMessage(builder.build());
    }

    public static String getProviderName() {
        return providerName;
    }

    public static String getProviderPassword() {
        return providerPassword;
    }
}
